using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using NextMind.Core.Event;
using System.Collections.Generic;
namespace NextMind.Examples.Utility
{
///
/// The EventNotifier is a component listening to all events (about devices connection, bluetooth, etc...).
/// It displays message on a Text element, colored regarding the event severity (Status, Warning, Error).
///
public class EventNotifier : MonoBehaviour
{
///
/// The canvas group on which text is displayed. Used to show/hide elements using its alpha value.
///
[SerializeField]
private CanvasGroup canvasGroup = null;
///
/// The text element.
///
[SerializeField]
private Text messageText = null;
///
/// The button used to hide the displayed message.
///
[SerializeField]
private Image closeButtonImage = null;
///
/// The background which will change color following events Severity as well.
///
[SerializeField]
private Image background = null;
///
/// The coroutine used to fade in/out the canvasGroup.
///
private Coroutine showCoroutine;
///
/// The events waiting to be displayed;
///
private Queue eventsQueue;
///
/// Are some events currently waiting to be displayed ?
///
private bool IsQueueEmpty => eventsQueue.Count == 0;
///
/// The coroutine used to manage the eventsQueue unqueueing.
///
private Coroutine unqueueCoroutine;
///
/// The last event added to the queue.
///
private EventBase lastEnqueuedEvent;
///
/// The event which message is currently displayed on the UI.
///
private EventBase currentlyDisplayedEvent;
///
/// The time allowed to display a message.
///
private float displayTime;
private const float maximumDisplayTime = 15f;
private const float minimumDisplayTime = 3f;
#region Unity methods
private void Start()
{
eventsQueue = new Queue();
var neuroManager = NeuroManager.Instance;
if (neuroManager != null)
{
// Start listening to wanted events.
neuroManager.onGlobalStatusEvent.AddListener(OnGlobalStatusEvent);
neuroManager.onDeviceEvent.AddListener(OnDeviceEvent);
}
}
private void OnDestroy()
{
var neuroManager = NeuroManager.Instance;
if (neuroManager != null)
{
// Stop listening to wanted events.
neuroManager.onGlobalStatusEvent.RemoveListener(OnGlobalStatusEvent);
neuroManager.onDeviceEvent.RemoveListener(OnDeviceEvent);
}
}
#endregion
#region Events handling
///
/// Method triggered when receiving a GlobalStatusEvent.
///
/// The event received
private void OnGlobalStatusEvent(EventBase globalEvent)
{
// Add to the queue of the events waiting to be displayed.
EnqueueEvent(globalEvent);
}
///
/// Method triggered when receiving a DeviceEvent.
///
/// The device's id
/// The event received
private void OnDeviceEvent(int deviceID, EventBase deviceEvent)
{
// Do not display contact events on Notifier.
if (deviceEvent is ContactEvent)
{
return;
}
// Add to the queue of the events waiting to be displayed.
EnqueueEvent(deviceEvent);
}
private void EnqueueEvent(EventBase evt)
{
// Don't add 2 identical events in a row. An identical event can be displayed only if the same message has been fully shown.
if (!IsQueueEmpty && evt == lastEnqueuedEvent
|| IsQueueEmpty && evt == currentlyDisplayedEvent)
{
return;
}
// Display messages during a shorter amount of time if the queue is not empty.
displayTime = currentlyDisplayedEvent != null ? minimumDisplayTime : maximumDisplayTime;
eventsQueue.Enqueue(evt);
lastEnqueuedEvent = evt;
// Start the unqueue coroutine if not already started.
if (unqueueCoroutine == null)
{
unqueueCoroutine = StartCoroutine(UnqueueMessages());
}
}
#endregion
private IEnumerator UnqueueMessages()
{
while (!IsQueueEmpty)
{
EventBase evt = eventsQueue.Dequeue();
currentlyDisplayedEvent = evt;
SetMessageUI(evt.ToString(), evt.Severity);
// If this event is the last to display, set the display time to the maximum.
if (IsQueueEmpty)
{
displayTime = maximumDisplayTime;
}
// Stop the coroutine if it is running.
if (showCoroutine != null)
{
StopCoroutine(showCoroutine);
}
// Show the panel.
showCoroutine = StartCoroutine(Show(true));
yield return new WaitUntil(() => showCoroutine == null);
}
currentlyDisplayedEvent = null;
unqueueCoroutine = null;
}
private void SetMessageUI(string text, EventBase.EventSeverity severity)
{
messageText.text = text;
switch (severity)
{
case EventBase.EventSeverity.Status:
// Blue
messageText.color = new Color32(0x00, 0x11, 0x7A, 0xFF);
background.color = new Color32(0xA8, 0xD0, 0xFF, 0xB2);
break;
case EventBase.EventSeverity.Warning:
// Yellow
messageText.color = new Color32(0x72, 0x3F, 0x00, 0xFF);
background.color = new Color32(0xFF, 0xDF, 0x99, 0xB2);
break;
case EventBase.EventSeverity.Error:
// Red
messageText.color = new Color32(0x7A, 0x00, 0x00, 0xFF);
background.color = new Color32(0xFF, 0x8F, 0x8F, 0xB2);
break;
}
// Apply the same color on the text and the button.
closeButtonImage.color = messageText.color;
}
///
/// Method triggered when user click on close button.
///
public void OnClickOnClose()
{
// Stop the coroutine if it is running.
if (showCoroutine != null)
{
StopCoroutine(showCoroutine);
}
// Fade the panel out.
showCoroutine = StartCoroutine(Show(false));
}
///
/// The coroutine fading in and out the message canvasGroup.
///
///
///
private IEnumerator Show(bool show)
{
float t = 0, duration = 1f, timer = 0f;
float startValue = canvasGroup.alpha;
float targetValue = show ? 1 : 0;
while (t < 1)
{
canvasGroup.alpha = Mathf.Lerp(startValue, targetValue, t);
timer += Time.deltaTime;
t = timer / duration;
yield return null;
}
canvasGroup.alpha = targetValue;
if (show)
{
timer = 0;
while (timer < displayTime)
{
timer += Time.deltaTime;
yield return null;
}
yield return StartCoroutine(Show(false));
}
showCoroutine = null;
}
}
}